package com.saturday.web.filter.xss;

import com.saturday.common.constants.CommonConsts;
import com.saturday.utils.PathUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;

/**
 * xss过滤器(可配置algorithm-算法、key-秘钥、excludeAttr*-xss排除参数列表)
 */
@Component
@Slf4j
public class XssFilter implements Filter {

    /**
     * 排除 xss过滤字段
     */
    private static final List<String> DEFAULT_ALLOWED_PARAM = Arrays.asList("artcCntntAdd", "artcCntnt", "bizDetailUrl", "viewRouter", "fromKeys", "toKeys", "formKey");

    // 排除请求（包含文件导入、批量导入、登录、菜单、退出）
    private static Set<String> DEFAULT_ALLOWED_PATHS = new HashSet() {
        {
        }

    };

    /**
     * xss json过滤器
     */
    private static XssValueFilter valueFilter = null;

    @Value("${xss.allowed.paths:}")
    private String allowedPaths;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 1、不过滤参数设置
        List<String> excludeAttr = new ArrayList<>();
        excludeAttr.addAll(DEFAULT_ALLOWED_PARAM);

        while (filterConfig.getInitParameterNames().hasMoreElements()) {
            String item = filterConfig.getInitParameterNames().nextElement();
            if (item.startsWith("excludeAttr")) {
                excludeAttr.add(filterConfig.getInitParameter(item));
            }
        }
        valueFilter = new XssValueFilter(excludeAttr);

        if (StringUtils.isNotEmpty(allowedPaths)) {
            String[] paths = allowedPaths.split(",");
            if (null != paths && paths.length > 0) {
                for (String path : paths) {
                    DEFAULT_ALLOWED_PATHS.add(path);
                }
            }
        }

        log.info("------XSS防护过滤器启动-------");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        String contentType = request.getContentType();
        String path = request.getRequestURI().substring(request.getContextPath().length());

        String isFeign = ((HttpServletRequest) req).getHeader(CommonConsts.FEIGN_CLIENT_KEY);
        // 如果是上传不用生成XSSHTTP对象--可在上传处理后在进行清洗
        if (path.contains("/actuator")
                || PathUtil.pathMatcher(path, DEFAULT_ALLOWED_PATHS)
                || (contentType != null && contentType.toLowerCase().startsWith("multipart/"))
                || "true".equals(isFeign)) {
            chain.doFilter(request, response);
        } else {
            log.info("request path：{}----Xss安全清洗开始", path);
            XssHttpServletRequestWrapper xssHttpServletRequestWrapper = new XssHttpServletRequestWrapper(request, valueFilter, false);
            log.info("path：{}----Xss安全清洗结束", path);
            chain.doFilter(xssHttpServletRequestWrapper, response);
        }
    }

    @Override
    public void destroy() {
    }
}
